package de.medieninf.sensimg;

import java.util.Vector;

/**
 * Central settings for application, singleton. Allows registering
 * in case settings change.
 * @author pb
 */
public final class Settings {
    /**
     * The singleton instance for settings.
     */
    private static Settings settings = new Settings();
    /**
     * Whether we activate the sensor.
     */
    private boolean sensor;
    /**
     * Whether we show the ball.
     */
    private boolean ball;
    /**
     * Whether we send acceleration data.
     */
    private boolean send;
    /**
     * Where to possibly send to.
     */
    private Vector sendUrls;
    /**
     * Which one of the possible sendUrls is selected.
     */
    private int currentSendUrlIndex;
    /**
     * Which ones are actually default on start up.
     */
    private String[] defaultSendUrls = {
        "150.162.202.87:9617",
        "150.162.202.69:9617",
        "150.162.202.81:9617",
        "150.162.202.81:9618",
        "192.168.0.185:9617",
    };
    /**
     * Which one is selected on start up.
     */
    static final int DEFAULT_SENDURLINDEX = 4;
    /**
     * From which places are images possible to retrieve.
     */
    private Vector recvUrls;
    /**
     * Which place do we actually use.
     */
    private int currentRecvUrlIndex;
    /**
     * Which ones are actually default on start up.
     */
    private String[] defaultRecvUrls = {
        "150.162.202.87:8082",
        "150.162.202.69:8082",
        "150.162.202.81:8082",
        "192.168.0.185:8082",
    };
    /**
     * Which one is active on start up.
     */
    static final int DEFAULT_RECVURLINDEX = 3;
    /**
     * Observer to be notified if settings values change.
     */
    private Vector updateRunnables;
    /**
     * Constructor constructing singleton instance only.
     */
    private Settings() {
        ball = false;
        sensor = false;
        send = false;
        sendUrls = new Vector();
        for (int i = 0; i < defaultSendUrls.length; i++) {
            sendUrls.addElement(defaultSendUrls[i]);
        }
        recvUrls = new Vector();
        for (int i = 0; i < defaultRecvUrls.length; i++) {
            recvUrls.addElement(defaultRecvUrls[i]);
        }
        currentSendUrlIndex = DEFAULT_SENDURLINDEX;
        currentRecvUrlIndex = DEFAULT_RECVURLINDEX;
        updateRunnables = new Vector();
    }

    /**
     * Get Settings singleton.
     * @return settings instance
     */
    public static Settings getSettings() {
        return settings;
    }

    /**
     * Should the ball be shown.
     * @return boolean
     */
    public boolean getBall() {
        return ball;
    }
    /**
     * Set whether ball should be shown.
     * @param pball boolean should it
     */
    public void setBall(final boolean pball) {
        if (this.ball != pball) {
            this.ball = pball;
            changed();
        }
    }

    /**
     * Should the sensor be on.
     * @return boolean
     */
    public boolean getSensor() {
        return sensor;
    }
    /**
     * Should the sensor be on.
     * @param psensor boolean should it
     */
    public void setSensor(final boolean psensor) {
        if (this.sensor != psensor) {
            this.sensor = psensor;
            changed();
        }
    }
    /**
     * Should the sender be on.
     * @return boolean
     */
    public boolean getSend() {
        return send;
    }
    /**
     * Should the sender be on.
     * @param psend boolean should it
     */
    public void setSend(final boolean psend) {
        if (this.send != psend) {
            this.send = psend;
            changed();
        }
    }
    /**
     * Where to send acceleration data to.
     * @return String
     */
    public String getCurrentSendUrl() {
        return (String) sendUrls.elementAt(currentSendUrlIndex);
    }
    /**
     * Where to send acceleration data to.
     * @return index
     */
    public int getCurrentSendUrlIndex() {
        return currentSendUrlIndex;
    }
    /**
     * Where to send acceleration data to.
     * @param psendUrl the URL
     * @return boolean true iff is new
     */
    public boolean setCurrentSendUrl(final String psendUrl) {
        boolean ret = false;
        if (!sendUrls.contains(psendUrl)) {
            sendUrls.addElement(psendUrl);
            ret = true;
        }
        currentSendUrlIndex = sendUrls.indexOf(psendUrl);
        changed();
        return ret;
    }
    /**
     * Add possibility where to send acceleration data to.
     * @param psendUrl the URL
     * @return boolean true iff is new
     */
    public boolean addSendUrl(final String psendUrl) {
        if (sendUrls.contains(psendUrl)) {
            return false;
        }
        sendUrls.addElement(psendUrl);
        return true;
    }
    /**
     * Where can acceleration data possibly be sent.
     * @return Array of possible URLs
     */
    public String[] getPossibleSendUrls() {
        String[] ret = new String[sendUrls.size()];
        sendUrls.copyInto(ret);
        return ret;
    }
    /**
     * Where to retrieve images from.
     * @return String
     */
    public String getCurrentRecvUrl() {
        return (String) recvUrls.elementAt(currentRecvUrlIndex);
    }
    /**
     * Where to retrieve images from.
     * @return index
     */
    public int getCurrentRecvUrlIndex() {
        return currentRecvUrlIndex;
    }
    /**
     * Where to retrieve images from.
     * @param precvUrl the URL
     * @return boolean true iff is new
     */
    public boolean setCurrentRecvUrl(final String precvUrl) {
        boolean ret = false;
        if (!recvUrls.contains(precvUrl)) {
            recvUrls.addElement(precvUrl);
            ret = true;
        }
        currentRecvUrlIndex = recvUrls.indexOf(precvUrl);
        changed();
        return ret;
    }
    /**
     * Add possibility where to retrieve images from.
     * @param precvUrl the URL
     * @return boolean true iff is new
     */
    public boolean addRecvUrl(final String precvUrl) {
        if (recvUrls.contains(precvUrl)) {
            return false;
        }
        recvUrls.addElement(precvUrl);
        return true;
    }
    /**
     * Where can images be retrieved from.
     * @return Array of possible URLs
     */
    public String[] getPossibleRecvUrls() {
        String[] ret = new String[recvUrls.size()];
        recvUrls.copyInto(ret);
        return ret;
    }

    /**
     * Register a callback for each change of the settings.
     * @param r Runnable a call back
     */
    public void registerUpdate(final Runnable r) {
        synchronized (updateRunnables) {
            if (!updateRunnables.contains(r)) {
                updateRunnables.addElement(r);
            }
        }
    }
    /**
     * Unregister a callback for each change of the settings.
     * @param r Runnable a call back
     */
    public void unregisterUpdate(final Runnable r) {
        synchronized (updateRunnables) {
            if (updateRunnables.contains(r)) {
                updateRunnables.removeElement(r);
            }
        }
    }
    /**
     * In case something has been changed inform the observers.
     */
    private void changed() {
        Runnable[] runnables;
        synchronized (updateRunnables) {
            runnables = new Runnable[updateRunnables.size()];
            updateRunnables.copyInto(runnables);
        }
        for (int i = 0; i < runnables.length; i++) {
            runnables[i].run();
        }
    }
}
